<?php
/**
 * 首页 dashboard 面板数据
 * Author: lyun
 * Date: 2018/3/30
 * Created by Panxsoft.
 */

namespace App\Http\Controllers\Admin\Customer;

use App\Http\Controllers\ApiController;
use App\Models\Customer\Customer;
use App\Models\Customer\DeviceAccount;
use App\Models\OpenWechat\WechatUser;
use App\Models\Panx\Product;
use App\Models\Panx\Record;
use App\Models\Panx\RecordType;
use App\Models\Panx\Visit;
use App\Models\Store\SkinRecord;
use App\Models\Store\Store;
use App\Models\Store\StorePivotWechatUser;
use App\Services\Assemblers\Admin\DashboardAssembler;
use App\Services\Repositories\Product\ProductRepository;
use App\Services\Repositories\SkinRecord\SkinRecordCountRepository;
use App\Services\Repositories\SkinRecord\SkinRecordRepository;
use App\Services\Repositories\VisitRepository;
use App\Services\Utils\Guard;
use App\Services\Utils\PanxCollection;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;


class DashboardController extends ApiController
{

    const ROUTES = [
        'index'             => 'api.admin.customer.dashboard.index',
        'user-skin-counts'  => 'api.admin.customer.dashboard.skin.counts',
        'store-skin-counts' => 'api.admin.customer.dashboard.store.skin.counts',
    ];
    /**
     * 首页 dashboard 面板数据
     * @test
     *
     * @param Request $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function index(Request $request)
    {
        $this->checkCustomer();

        $customer = Guard::customerAdmin()->customer;

        // 检测是否是虚拟供应商
        $is_virtual_provider = $customer->isProviderTypeVirtualProvider();
            $this->checkUnless($is_virtual_provider, trans('admin.is_virtual_provider'));

        $stores = $customer->stores()
            ->get(['id', 'type', 'name', 'address', 'visit', 'store_img']);

        $store_ids = $stores->pluck('id');

        $skin_record = $this->getSkinRecordGroupByStoreId($store_ids); // 测肤记录

        $record = $this->getRecordGroupByStoreId($store_ids); // 试戴记录

        $stores = $this->transformStores($stores, $record, $skin_record);

        /**
         * 使用get (0.1900s) usage: 19.27MB, peak: 19.30MB
         * 使用cursor (0.1410s) usage: 19.14MB, peak: 19.16MB
         */
        $wechat_user_profiles = [];
        foreach ( $this->queryWechatUsersBuilder($store_ids)->cursor() as $wechat_user )
        {
            $wechat_user_profiles [] = $wechat_user;
        }
        $wechat_user_profiles = collect($wechat_user_profiles);

        $profiles = DashboardAssembler::assembleWxUserProfiles($wechat_user_profiles);

        $products = (new ProductRepository())->countCustomerTryOn($customer);

        return $this->response(compact(
            'stores', 'products',  'profiles'
        ));
    }

    /**
     * @deprecated - 前端已不再显示访客统计
     *
     * 返回 访客统计数据
     *
     * @param Request $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function getVisitCounts(Request $request)
    {
        /** @var Customer $customer */
        $customer = Guard::customerAdmin()->customer;

        $group_type = $request->group_type?:'month';
        $store_ids = $customer->stores()->pluck('id')->all();

        $visit_counts = (new VisitRepository)->queryCustomerOrStoreVisits($store_ids, $group_type);

        return $this->response(compact('visit_counts'));
    }

    /**
     * 返回 访客客户所有店铺的测肤统计数据
     * @test
     *
     * @param Request $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function getCustomerAllStoreSkinCounts(Request $request)
    {
        $this->checkCustomer();

        /** @var Customer $customer */
        $customer = Guard::customerAdmin()->customer;

        $group_type = $request->group_type?:'month';

        $store_ids = $customer->stores()->pluck('id')->all();

        $skin_record_counts = (new SkinRecordRepository())->queryCustomerOrStoreSkinRecords($store_ids, $group_type);

        return $this->response(compact('skin_record_counts'));
    }
    
    /**
     * 返回 客户下各店铺的测肤统计
     * @test
     *
     * @param Request $request
     *
     * @throws \Exception
     * @return array|\Illuminate\Http\Response
     */
    public function getStoresSkinCounts(Request $request)
    {
        $this->checkCustomer();

        /** @var Customer $customer */
        $customer = Guard::customerAdmin()->customer;

        $store_count_skin = (new SkinRecordCountRepository)->storeCountSkin($customer);

        return $this->response(compact('store_count_skin'));
    }

    /**
     * @param \Illuminate\Support\Collection $store_ids
     * @return WechatUser
     */
    private function queryWechatUsersBuilder($store_ids)
    {
        $store_ids = $store_ids->all();

        $wechat_user_ids = (new StorePivotWechatUser())
            ->whereIn('store_id', $store_ids)
            ->pluck('wechat_user_id')
            ->all();

        /** @var WechatUser $wechat_users_collection */
        $wechat_users = (new WechatUser)
            ->whereIn('id', $wechat_user_ids)
            ->filterSkinRecordByStores(1, $store_ids)  // 有无测肤记录，必须有测肤记录的 has_skin_record = 1
            ->select([
                'id', 'sex', 'city', 'born_at',
            ]);

        return $wechat_users;
    }

    /**
     * @param $store_ids
     * @return Collection|\Illuminate\Support\Collection|static[]
     */
    private function getSkinRecordGroupByStoreId($store_ids)
    {
        $skin_record = (new SkinRecord)
            ->leftJoin('stores', 'stores.id', '=', 'store_id')
            ->select([
                'stores.id AS id',
                DB::raw('COUNT(*) AS skin_record_count'),
            ])
            ->whereIn('stores.id', $store_ids)
            ->groupBy('id')
            ->get();
        return $skin_record;
    }

    /**
     * @param $store_ids
     * @return Collection|\Illuminate\Support\Collection|static[]
     */
    private function getRecordGroupByStoreId($store_ids)
    {
        $record = (new Record)
            ->leftJoin('device_accounts', 'device_accounts.id', '=', 'recorderable_id')
            ->leftJoin('stores', 'stores.id', '=', 'device_accounts.store_id')
            ->select([
                'stores.id AS id',
                DB::raw('COUNT(*) AS try_on'),
            ])
            ->whereIn('stores.id', $store_ids)
            ->where([
                'recorderable_type' => class_basename(DeviceAccount::class),
                'record_type_id'    => RecordType::PRODUCT_TRYON
            ])
            ->groupBy('id')
            ->get();
        return $record;
    }

    /**
     * @param Collection $stores
     * @param Collection $record
     * @param Collection $skin_record
     * @return mixed
     */
    private function transformStores(Collection $stores, Collection $record,Collection $skin_record)
    {
        // 改用数组 ，效率 跟在transform 中用Collection的where查询几乎一样
        $skin_record = $skin_record->groupBy('id')->toArray();
        $record = $record->groupBy('id')->toArray();

        $stores_transform = $stores->transform(function (Store $store) use ($record, $skin_record) {

            $store->try_on = $record[$store->id][0]['try_on'] ?? 0;
            $store->skin_record_count = $skin_record[$store->id][0]['skin_record_count'] ?? 0;

            return $store;
        });

        $stores = $stores_transform->sortByDesc('try_on')->values()->all();
        return $stores;
    }

}
